package com.example.lightble;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.util.Log;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;


public class GattManager {

	public static String UUID_SERVICE = "00001910-0000-1000-8000-00805f9b34fb";
    public static String UUID_READ = "0000fff4-0000-1000-8000-00805f9b34fb";
    public static String UUID_WRITE = "0000fff2-0000-1000-8000-00805f9b34fb";
   
    private ConcurrentLinkedQueue<GattOperation> mQueue;
    private ConcurrentHashMap<String, BluetoothGatt> mGatts;  //GATT安卓层面上已连接的设备列�?
    private ArrayList<BluetoothGatt> mSendPasswdList;
    private GattOperation mCurrentOperation;
    private OperationOutThread mOperationOutThread;
    private Context mContext;
    private Handler mBleConnectHandler;
	private static final String TAG = "sno";
	private boolean isDriveRunning=false;  
    public GattManager(Context cxt,Handler handler) {
        mQueue = new ConcurrentLinkedQueue<GattOperation>();
        mGatts = new ConcurrentHashMap<String, BluetoothGatt>();
        mSendPasswdList=new ArrayList<BluetoothGatt>();
        mCurrentOperation = null;
        mContext=cxt;
        mBleConnectHandler=handler;
    }
    private void sendPassWdLists()
    {
    	for(BluetoothGatt gatt:mSendPasswdList)
    	{
             Message msg1=mBleConnectHandler.obtainMessage(BlueToothService.BLEGATT_CONN_SEND_PASSWD);//连续发�?多个.
             msg1.obj=gatt.getDevice();
             mBleConnectHandler.sendMessage(msg1);
    	}
    	mSendPasswdList.clear();
    }
    public void disConnectBle(String address)
    {
    	 if(mGatts.containsKey(address))
    	 {
    		 	BluetoothGatt gatt= mGatts.get(address);
    			gatt.disconnect();
    			gatt.close();
    			mGatts.remove(address);
    			gatt=null;
    			System.gc(); //TODO 测试是否应该让系统回�?..
    			Log.i(TAG, "GattManager::disconnectBle -device address: "+address);
    	 }else{
    		 Log.w(TAG, "GattManager::disconnectBle no device: "+address);
    	 }
    	
    	 for(GattOperation op :mQueue) 
    	 {
    		 if(op.getDevice().getAddress().equals(address))
    		 {
    			  mQueue.remove(op);
    			  Log.i("sno","取消操作 :" + op.getTag());
    		 }
         }
    	 if( mQueue.size() == 0 && isDriveRunning==false) {
             mCurrentOperation = null;
         }
    }
    public  void sendDataToAddress(byte[] bytes,String address)
    {
    	if(bytes==null){
    		Log.e("sno","GattManager:: sendDataToAddress bytes==null");
    		return ;
    	}
    	 if(mGatts.containsKey(address))
    	 {
    		 	BluetoothGatt gatt= mGatts.get(address);
    		 	BluetoothGattService service = gatt.getService(UUID.fromString(UUID_SERVICE));  
    	        if(service!=null) //如果在发送的时�?, 突然断开�?service就是null�?这里判断.
    	        {
    	        	List<BluetoothGattCharacteristic> gattCharacteristics = service.getCharacteristics();
    	     		for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) 
    	     		{
    	             	if(gattCharacteristic.getUuid().toString().equals(UUID_WRITE))
    	             	{
    	             		gattCharacteristic.setValue(bytes);
    	             		gatt.writeCharacteristic(gattCharacteristic);
    	                 	Log.i("sno","GattManager::sendDataToAddress to:"+gatt.getDevice().getName());
    	    	            break;
    	             	}
    	           }
    	        }else
    	        	Log.w(TAG, "GattManager::sendDataToAddress -service==null");
    	 }else{
    		 Log.w(TAG, "GattManager::sendDataToAddress no device: "+address);
    	 }
    }
    public synchronized void queue(GattOperation gattOperation) {
        mQueue.add(gattOperation);
        drive();
    }
    private synchronized void drive() {
        if(mCurrentOperation != null) {  //�?��operation执行完毕, 执行下一个operation
        	Log.i("sno","tried to drive, but currentOperation was not null, return;!!!");
            return;
        }
        cancelOperationOutThread();
        if( mQueue.size() == 0) {
        	Log.i("sno","Queue empty, drive loop stopped.");
            mCurrentOperation = null;
            isDriveRunning=false;
            sendPassWdLists();
            return;
        }
        final GattOperation operation = mQueue.poll();
        setCurrentOperation(operation);
        isDriveRunning=true;

        mOperationOutThread=new OperationOutThread();
        mOperationOutThread.start();
    
        final BluetoothDevice device = operation.getDevice();
        if(mGatts.containsKey(device.getAddress())==false)
        {
        	  Log.i("sno","�?���?��新的连接: "+operation.getTag()+" mQueue.size(): " + mQueue.size());
        	//  BluetoothGatt gatt= device.connectGatt(mContext, true,new MyBlueToothGattCallback());
        	  BluetoothGatt gatt= device.connectGatt(mContext, true,mBlueToothGattCallback);
        	  mGatts.put(gatt.getDevice().getAddress(), gatt);
        }else{  //如果已经存在,则说明连接上.
        	 setCurrentOperation(null);
             drive();
        }
    }
    /**
     * 如果超时�? 但还没有连接�?重连或�?�?
     */
    private void operationTimeOut()
    {
    	 if(mCurrentOperation != null) 
    	 {
             mQueue.remove(mCurrentOperation);
             Log.i("sno","OperationTimeout::"+mCurrentOperation.getDevice().getAddress()+" 已超�?Queue10000 剩余: "+mQueue.size());
             
             Message msg1=mBleConnectHandler.obtainMessage(BlueToothService.BLEGATT_CONN_TIMEOUT_MESSAGE);
             msg1.obj=mCurrentOperation.getDevice();
             mBleConnectHandler.sendMessage(msg1);
         }
    	 setCurrentOperation(null);
         drive();
    }
    private  MyBlueToothGattCallback  mBlueToothGattCallback =new MyBlueToothGattCallback();
     private class MyBlueToothGattCallback extends  BluetoothGattCallback
     {
    	 @Override
    	public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
    		// TODO Auto-generated method stub
    		super.onReadRemoteRssi(gatt, rssi, status);
    	}
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) 
        {
            super.onConnectionStateChange(gatt, status, newState);
        	Log.i(TAG, gatt.getDevice().getName()+" onConnectionStateChange status:"+status+"newState"+newState);
            Message msg1=mBleConnectHandler.obtainMessage(BlueToothService.BLEGATT_CONN_CHANGE_MESSAGE);
            msg1.obj=gatt.getDevice();
            msg1.arg1=status;
            msg1.arg2=newState;
            mBleConnectHandler.sendMessage(msg1);
 
            if (newState == BluetoothProfile.STATE_CONNECTED) 
            {
            		if(status==133)
            		{
            		} else{
            			Log.i(TAG, gatt.getDevice().getName()+" start discoverServices="+gatt.discoverServices());  //连接好后, 直接去找services	
            		}
            } 
            else if (newState == BluetoothProfile.STATE_DISCONNECTED)   //设备已断�?断开的Operation执行�?
            {  
	            	setCurrentOperation(null);
 					drive();
            }
        }
        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) 
        {
            super.onServicesDiscovered(gatt, status);
            Log.i("sno","services discovered, status: " + status);
            if (status == BluetoothGatt.GATT_SUCCESS) 
            { 
            		BluetoothGattService service = gatt.getService(UUID.fromString(UUID_SERVICE));
            		List<BluetoothGattCharacteristic> gattCharacteristics = service.getCharacteristics();   
                    for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) 
                    {
			                	if(gattCharacteristic.getUuid().toString().equals(UUID_WRITE))
			                	{
			                		Log.i("sno","服务已找�? -device:"+gatt.getDevice().getName());
			                	}
			                	if(gattCharacteristic.getUuid().toString().equals(UUID_READ))
			                	{
			                		 gatt.setCharacteristicNotification(gattCharacteristic, true);
			                		 List<BluetoothGattDescriptor> descriptors= gattCharacteristic.getDescriptors();
			                		 for(BluetoothGattDescriptor descriptor:descriptors)
					    	         {
			                				descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
			                				gatt.writeDescriptor(descriptor); 
					    	         }
			                	}
                    }
            } else {
					   Log.w(TAG, gatt.getDevice().getName()+" onServicesDiscovered received error: " + status);
					   if(status!=129){    //如果等于129,则会在调用连接状态回�? 在那里发送连接失败的标志.再次重连.
				            Message msg1=mBleConnectHandler.obtainMessage(BlueToothService.BLEGATT_CONN_ERROR_MESSAGE);
				            msg1.obj=gatt.getDevice();
				            msg1.arg1=status;
				            mBleConnectHandler.sendMessage(msg1);
					   }
            }
        }
        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);
            Log.i("sno","Characteristic " +"written to on device " + gatt.getDevice().getAddress()+" status:"+status);
        }
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) 
        {
            super.onCharacteristicChanged(gatt, characteristic);
            Log.i("sno","onCharacteristicChanged  recv data:"+gatt.getDevice().getName());
        	byte[] data = characteristic.getValue();
        	
            Message msg1=mBleConnectHandler.obtainMessage(BlueToothService.BLEGATT_CONN_RCV_DATA);
            msg1.obj=new DeviceInfo(gatt.getDevice(),data);
            msg1.arg1=data.length;
            mBleConnectHandler.sendMessage(msg1);
        }
        @Override
        public void onDescriptorWrite(BluetoothGatt gatt,BluetoothGattDescriptor descriptor, int status) {
        	// TODO Auto-generated method stub
        	super.onDescriptorWrite(gatt, descriptor, status);
        	Log.i("sno","onDescriptorWrite status:"+status+" device "+gatt.getDevice().getAddress());
        	if(mCurrentOperation!=null)
    		{
    				  if(mSendPasswdList.contains(gatt)==false)  //统一发�?密码
    					  mSendPasswdList.add(gatt);
    				 
    		            Message msg1=mBleConnectHandler.obtainMessage(BlueToothService.BLEGATT_CONN_OK_MESSAGE);
    		            msg1.obj=gatt.getDevice();
    		            mBleConnectHandler.sendMessage(msg1);
    		}else{
    			Log.e("sno","mCurrentOperaion==null");
    		}
        	cancelOperationOutThread();
            mBleConnectHandler.postDelayed(new Runnable() {
       				
       				@Override
       				public void run() {
       					// TODO Auto-generated method stub
       					Log.i("sno","HHHHHHHHHHHHDDDDDDDDHHHHHHHHHHH200HHHHHH.");
       					setCurrentOperation(null);
       					drive();
       				}
       		}, 30);
        }
    };
    public synchronized void setCurrentOperation(GattOperation currentOperation) {
        mCurrentOperation = currentOperation;
        Log.i("sno","mcurrentOperation is " +mCurrentOperation);
    }
	
    private void cancelOperationOutThread()
    {
		 if(mOperationOutThread != null) {
	        	mOperationOutThread.cancelWait();
	        	mOperationOutThread=null;
	     }
    }
	class OperationOutThread extends Thread
	{
	    public OperationOutThread() 
	    {
	        super();
	    }
	    Object obj= new Object();
	   boolean isInterupted=false;
	   
	    public void cancelWait()
	    {
	    	synchronized (obj) {
	    		isInterupted=true;
	    		obj.notify();
			}
	    }
	    public void run() {
	        synchronized (this) {
	            synchronized (obj) {
	            	try {
	            			 isInterupted=false;
	            			 obj.wait(3000);  //3秒钟超时就重�?
	            			 if(isInterupted){
		            		 }else{  //超时.
		            			 operationTimeOut();
		            		 }
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
	        }
	    }
	}
}
